﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlServerCe;
using System.Reflection;
using System.Threading;

namespace Tui
{
    [AttributeUsage(AttributeTargets.Class)]
    public class TableNameAttribute : Attribute
    {
        public string TableName { get; private set; }
        public TableNameAttribute(string tableName) { TableName = tableName; }
    }

    public class BusinessObjectSupport
    {
        public Func<SqlCeConnection> ConnectionGet { get; private set; }
        public Action<SqlCeConnection> ConnectionRelease { get; private set; }
        public string TableName { get; private set; }

        private static Dictionary<Type, BusinessObjectSupport> _allSupporters = new Dictionary<Type, BusinessObjectSupport>();
        internal static BusinessObjectSupport GetSupporter(Type t)
        {
            BusinessObjectSupport bos;
            if (!_allSupporters.TryGetValue(t, out bos))
            {
                if (t == typeof(object)) return new BusinessObjectSupport() { ConnectionGet = delegate { throw new Exception("Missing static method - SqlCeConnection ConnectionGet(); OR void ConnectionRelease(SqlCeConnection);."); } };

                var tnas = t.GetCustomAttributes(typeof(TableNameAttribute), false);
                string tableName = (tnas.Length > 0) ? ((TableNameAttribute)tnas[0]).TableName : t.Name/* t.Name*/;

                var ms = t.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

                var cgm = ms.Where(m => m.Name.Equals("ConnectionGet", StringComparison.OrdinalIgnoreCase) && m.ReturnType == typeof(SqlCeConnection) && m.GetParameters().Length == 0).FirstOrDefault();
                Func<SqlCeConnection> connectionGet = (cgm != null) ? (Func<SqlCeConnection>)Delegate.CreateDelegate(typeof(Func<SqlCeConnection>), null, cgm) : null;

                var crm = ms.Where(m => m.Name.Equals("ConnectionRelease", StringComparison.OrdinalIgnoreCase) && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(SqlCeConnection)).FirstOrDefault();
                Action<SqlCeConnection> connectionRelease = (crm != null) ? (Action<SqlCeConnection>)Delegate.CreateDelegate(typeof(Action<SqlCeConnection>), null, crm) : null;

                if (connectionGet == null) connectionGet = GetSupporter(t.BaseType).ConnectionGet;
                if (connectionRelease == null) connectionRelease = GetSupporter(t.BaseType).ConnectionRelease;


                Dictionary<Type, BusinessObjectSupport> allSupporters = new Dictionary<Type, BusinessObjectSupport>(_allSupporters);
                allSupporters[t] = bos = new BusinessObjectSupport() { TableName = tableName, ConnectionGet = connectionGet, ConnectionRelease = connectionRelease };
                Interlocked.Exchange(ref _allSupporters, allSupporters);
            }
            return bos;
        }

    }
}
